package com.share.thread;

/**
 * @desc: 转账 演示死锁 通过 hashcode或者id来解决死锁问题
 * @author:caifan
 * @date:2022/6/7
 */
public class TransferMoney implements Runnable {

    /**
     * 标记位
     */
    int flag;

    static Account a = new Account(123, 500);
    static Account b = new Account(423, 500);

    public static void main(String[] args) throws InterruptedException {
        TransferMoney transferMoney1 = new TransferMoney();
        TransferMoney transferMoney2 = new TransferMoney();
        transferMoney1.flag = 1;
        transferMoney2.flag = 0;
        Thread t1 = new Thread(transferMoney1);
        Thread t2 = new Thread(transferMoney2);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("a的余额:" + a.balance);
        System.out.println("b的余额:" + b.balance);
    }

    @Override
    public void run() {
        if (flag == 1) {
            transferMoney(a, b, 100);
        } else if (flag == 0) {
            transferMoney(b, a, 150);
        }
    }

    /**
     * 转账操作
     * @param from 转账方
     * @param to 收款方
     * @param amount 金额
     */
    public static void transferMoney(Account from, Account to, int amount) {
        // 死锁的解决方法 通过hashcode或者id确定锁顺序
        int fromHash = System.identityHashCode(from);
        int toHash = System.identityHashCode(to);

        /**
        // 第一版
        if (fromHash < toHash) {
            synchronized (from) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                synchronized (to) {
                    if (from.balance - amount < 0) {
                        System.out.println("余额不足，转账失败");
                        return;
                    }
                    from.balance = from.balance - amount;
                    to.balance = to.balance + amount;
                    System.out.println("成功转账:" + amount + "元");
                }
            }
        } else if (fromHash > toHash) {
            synchronized (to) {
                // 用于模拟死锁
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (from) {
                    if (from.balance - amount < 0) {
                        System.out.println("余额不足，转账失败");
                        return;
                    }
                    from.balance = from.balance - amount;
                    to.balance = to.balance + amount;
                    System.out.println("成功转账:" + amount + "元");
                }
            }
        }
        */

        // 第二版 破坏循环等待条件解决死锁
        Account left = from;
        Account right = to;
        if (fromHash > toHash) {
            left = to;
            right = from;
        }
        synchronized (left) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (right) {
                if (from.balance - amount < 0) {
                    System.out.println("余额不足，转账失败");
                    return;
                }
                from.balance = from.balance - amount;
                to.balance = to.balance + amount;
                System.out.println("成功转账:" + amount + "元");
            }
        }

    }

    static class Account {
        int id;
        int balance;

        public Account(int id, int balance) {
            this.id = id;
            this.balance = balance;
        }
    }
}
